package com.nanyang.tms.mq.listener.importforecast;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ConverterUtils;
import com.nanyang.common.core.dict.CommonEnum;
import com.nanyang.common.core.domain.ApiResult;
import com.nanyang.common.core.exception.ServiceException;
import com.nanyang.common.tool.utils.convert.BeanUtils;
import com.nanyang.tms.api.dto.request.dataimport.DataImportLineRequest;
import com.nanyang.tms.api.dto.request.dataimport.DataImportUpdateRequest;
import com.nanyang.tms.api.dto.request.forecast.ForecastDeclareAddReuqest;
import com.nanyang.tms.api.dto.request.forecast.ForecastInfoAddRequest;
import com.nanyang.tms.api.dto.request.forecast.ForecastReceiverAddRequest;
import com.nanyang.tms.api.dto.request.forecast.ForecastSenderAddRequest;
import com.nanyang.tms.api.dto.request.forecast.ForecastVolumeAddReuqest;
import com.nanyang.tms.api.service.dataimport.DataImportRpcService;
import com.nanyang.tms.api.service.forecast.ForecastCoreRpcService;
import com.nanyang.tms.mq.listener.message.DataImportMessage;

import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ForecastReadListener implements ReadListener<ForecastExcelDTO>{
	 private List<ForecastInfoAddRequest> cachedDataList = new ArrayList<>();
	 private List<DataImportLineRequest> successList=new ArrayList<>();
	 private List<DataImportLineRequest> failList=new ArrayList<>();
	 private DataImportMessage dataImportMessage;
	 private ForecastCoreRpcService  forecastCoreRpcService;
	 private DataImportRpcService dataImportRpcService;
	 public ForecastReadListener(ForecastCoreRpcService  forecastCoreRpcService,DataImportRpcService dataImportRpcService,DataImportMessage dataImportMessage){
		 this.forecastCoreRpcService=forecastCoreRpcService;
		 this.dataImportRpcService=dataImportRpcService;
		 this.dataImportMessage=dataImportMessage;
	 }
	@Override
	public void invoke(ForecastExcelDTO data, AnalysisContext context) {
		Integer rowNumber = context.readSheetHolder().getApproximateTotalRowNumber();
		// 设置execl最多5000行（含表头）
		if (rowNumber > 5000) {
			throw new ExcelAnalysisException("超出总行数限制，总行数为：" + rowNumber);
		}
		
		 ForecastInfoAddRequest forecastInfo=null;
		 Optional<ForecastInfoAddRequest> opt = cachedDataList.stream().filter(x -> x.getCustomerNo().equals(data.getCustomerNo())).findFirst();
		 if(opt != null && opt.isPresent()){
			 forecastInfo= opt.get();
		 }
		 if(ObjectUtils.isNotEmpty(forecastInfo)){
			ForecastVolumeAddReuqest forecastVolumeAddReuqest = new ForecastVolumeAddReuqest();
			BeanUtils.copyProperties(data, forecastVolumeAddReuqest);
			forecastInfo.getVolumes().add(forecastVolumeAddReuqest);
		}else{
			cachedDataList.add(bulildForecastInfoAddRequest(data,dataImportMessage));
		}
	}
	@Override
	public void invokeHead(Map<Integer, ReadCellData<?>> headMapCell, AnalysisContext context){
		Map<Integer, String> headMap = ConverterUtils.convertToStringMap(headMapCell, context);
        try {
			Map<Integer, String> head =  getIndexNameMap(ForecastExcelDTO.class);
			 Set<Integer> keySet = head.keySet();  //解析到的excel表头和实体配置的进行比对
		        for (Integer key : keySet) {
		            if (StringUtils.isEmpty(headMap.get(key))) {
		                throw new ExcelAnalysisException("解析excel出错，请传入正确格式的excel");
		            }
		            if (!headMap.get(key).equals(head.get(key))) {
		                throw new ExcelAnalysisException("解析excel出错，请传入正确格式的excel");
		            }
		        }
		} catch (NoSuchFieldException e) {
			throw new ExcelAnalysisException("解析excel出错，请传入正确格式的excel");
		} 
	}

	@Override
	public void doAfterAllAnalysed(AnalysisContext context) {
		   if (CollectionUtils.isNotEmpty(cachedDataList)) {
			          for(ForecastInfoAddRequest forecastInfoAddRequest:cachedDataList){
			        	  try {
			        		  forecastInfoAddRequest.setNum(forecastInfoAddRequest.getVolumes().size());
			        		  ApiResult<Boolean> insertForecast = forecastCoreRpcService.insertForecast(forecastInfoAddRequest);
				        	  DataImportLineRequest result =new DataImportLineRequest();
				        	  result.setIndexCode(forecastInfoAddRequest.getCustomerNo());
				        	  result.setResult(insertForecast.getMessage());
				        	  if(CommonEnum.REQUEST_SUCCESS.getCode() == insertForecast.getCode()){
				        		  log.info("客户单号：{},导入成功",forecastInfoAddRequest.getCustomerNo());
				        		  successList.add(result);
				        	  }else{
				        		  log.info("客户单号：{},导入失败，失败原因：{}",forecastInfoAddRequest.getCustomerNo(),insertForecast.getMessage());
				        		  failList.add(result);
				        	  }
						} catch (Exception e) {
							  DataImportLineRequest result =new DataImportLineRequest();
				        	  result.setIndexCode(forecastInfoAddRequest.getCustomerNo());
				        	  result.setResult(CommonEnum.REQUEST_FAIL.getMessage());
			        		  log.info("客户单号：{},导入失败，失败原因：{}",forecastInfoAddRequest.getCustomerNo(),e.getMessage());
							  failList.add(result);
						}
			        	
			          }
			          DataImportUpdateRequest dataImportUpdateRequest = new DataImportUpdateRequest();
			          try {
				          dataImportUpdateRequest.setId(dataImportMessage.getId());
				          dataImportUpdateRequest.setStatus(1);
				          dataImportUpdateRequest.setResult("执行完成");
				          dataImportUpdateRequest.setTotalNum(cachedDataList.size());
				          dataImportUpdateRequest.setFailNum(failList.size());
				          dataImportUpdateRequest.setFailLines(failList);
				          dataImportUpdateRequest.setSuccessNum(successList.size());
				          dataImportUpdateRequest.setSuccessLines(successList);
				          ApiResult<Boolean> updateImportFileReuslt = dataImportRpcService.updateImportFileReuslt(dataImportUpdateRequest);
				          if(CommonEnum.REQUEST_SUCCESS.getCode() != updateImportFileReuslt.getCode()){
				        	  throw new ServiceException(updateImportFileReuslt.getCode(), updateImportFileReuslt.getMessage());
				          }
					} catch (Exception e) {
						log.error("更新执行结果失败，请手动处理，执行结果的参数：{},失败原因:{}", dataImportUpdateRequest.toString(),e.getMessage(),e);
					}
			          

	        }
	}
	@Override
	public void onException(Exception exception, AnalysisContext context) throws Exception {
		 DataImportUpdateRequest dataImportUpdateRequest = new DataImportUpdateRequest();
		 dataImportUpdateRequest.setId(dataImportMessage.getId());
         dataImportUpdateRequest.setStatus(2);
         dataImportUpdateRequest.setTotalNum(cachedDataList.size());
         dataImportUpdateRequest.setFailNum(failList.size());
         dataImportUpdateRequest.setFailLines(failList);
         dataImportUpdateRequest.setSuccessNum(successList.size());
         dataImportUpdateRequest.setSuccessLines(successList);
         dataImportUpdateRequest.setResult("执行失败，请重新导入："+exception.getMessage());
         
         try {
            dataImportRpcService.updateImportFileReuslt(dataImportUpdateRequest);
		} catch (Exception e) {
			log.error("更新执行结果失败，请手动处理，执行结果的参数：{},失败原因:{}", dataImportUpdateRequest.toString(),e.getMessage(),e);
		}
         ReadListener.super.onException(exception, context);
		
		
		
	}

	private ForecastInfoAddRequest  bulildForecastInfoAddRequest(ForecastExcelDTO data,DataImportMessage dataImportMessage){
		ForecastInfoAddRequest forecastInfoAddRequest=new ForecastInfoAddRequest();
		ForecastSenderAddRequest sender=new ForecastSenderAddRequest();
		ForecastReceiverAddRequest receiver=new ForecastReceiverAddRequest();
		List<ForecastVolumeAddReuqest> volumes=new ArrayList<>();
		ForecastVolumeAddReuqest forecastVolumeAddReuqest=new ForecastVolumeAddReuqest();
		BeanUtils.copyProperties(data, forecastInfoAddRequest);
		forecastInfoAddRequest.setWeight(data.getCustomerWeight());
		BeanUtils.copyProperties(data, receiver);
		BeanUtils.copyProperties(data,sender);
		BeanUtils.copyProperties(data,forecastVolumeAddReuqest);
		volumes.add(forecastVolumeAddReuqest);
		forecastInfoAddRequest.setVolumes(volumes);
		forecastInfoAddRequest.setReceiver(receiver);
		forecastInfoAddRequest.setSender(sender);
		List<ForecastDeclareAddReuqest> declares=new ArrayList<>();
		
		if(StringUtils.isNotEmpty(data.getSku1())){
			ForecastDeclareAddReuqest declare1=new ForecastDeclareAddReuqest();
			declare1.setSku(data.getSku1());
			declare1.setNameCn(data.getNameCn1());
			declare1.setNameEn(data.getNameEn1());
			declare1.setQuantity(data.getQuantity1());
			declare1.setPrice(data.getPrice1());
			declare1.setUnitCode(data.getUnitCode1());
			declare1.setTotalPrice(data.getTotalPrice1());
			declare1.setWeight(data.getDeclareWeight1());
			declares.add(declare1);
		}
		if(StringUtils.isNotEmpty(data.getSku2())){
			ForecastDeclareAddReuqest declare2=new ForecastDeclareAddReuqest();
			declare2.setSku(data.getSku2());
			declare2.setNameCn(data.getNameCn2());
			declare2.setNameEn(data.getNameEn2());
			declare2.setQuantity(data.getQuantity2());
			declare2.setPrice(data.getPrice2());
			declare2.setUnitCode(data.getUnitCode2());
			declare2.setTotalPrice(data.getTotalPrice2());
			declare2.setWeight(data.getDeclareWeight2());
			declares.add(declare2);
		}
		if(StringUtils.isNotEmpty(data.getSku3())){
			ForecastDeclareAddReuqest declare3=new ForecastDeclareAddReuqest();
			declare3.setSku(data.getSku3());
			declare3.setNameCn(data.getNameCn3());
			declare3.setNameEn(data.getNameEn3());
			declare3.setQuantity(data.getQuantity3());
			declare3.setPrice(data.getPrice3());
			declare3.setUnitCode(data.getUnitCode3());
			declare3.setTotalPrice(data.getTotalPrice3());
			declare3.setWeight(data.getDeclareWeight3());
			declares.add(declare3);
		}
		forecastInfoAddRequest.setDeclares(declares);
		forecastInfoAddRequest.setCompanyCode(dataImportMessage.getCompanyCode());
		forecastInfoAddRequest.setPin(dataImportMessage.getPin());
		forecastInfoAddRequest.setIp("127.0.0.1");
		return forecastInfoAddRequest;
		
	}
	public Map<Integer, String> getIndexNameMap(Class clazz) throws NoSuchFieldException {
	     Map<Integer, String> result = new HashMap<>();
	     Field field;
	     Field[] fields = clazz.getDeclaredFields();     //获取类中所有的属性
	     for (int i = 0; i < fields.length; i++) {
	         field = clazz.getDeclaredField(fields[i].getName());
	         field.setAccessible(true);
	         ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);//获取根据注解的方式获取ExcelProperty修饰的字段
	         if (excelProperty != null) {
	             int index = excelProperty.index();         //索引值
	             String[] values = excelProperty.value();   //字段值
	             StringBuilder value = new StringBuilder();
	             for (String v : values) {
	                 value.append(v);
	             }
	             result.put(index, value.toString());
	         }
	     }
	     return result;

    
}
}